//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "config.h"
#include "bulverde.h"
#include "time.h"
#include "irq.h"

/* jiffies should be defined as volatile */
volatile unsigned long jiffies=0;
volatile unsigned long jiffies_div10=0;

void TimerInit(void)
{
    u32 old_rcnr = __REG(RTC_BASE_PHYSICAL+RCNR_OFFSET);

    /* enable 32-kHz oscillator on */
    __REG(CLK_BASE_PHYSICAL+OSCC_OFFSET) = OSCC_OON;

    /* disable timer interrupts and clear the AL and HZ bits*/
    __REG(RTC_BASE_PHYSICAL+RTSR_OFFSET) = (RTSR_AL | RTSR_HZ);

    /* put the counter to 0 */
    /* strange enough, this doesn't seem to work -- Erik */
    /* RCNR = 0x0; */

    /* RCNR writes may be delayed by a 32-kHz clock cycle */
    __REG(RTC_BASE_PHYSICAL+RCNR_OFFSET) = 0x0;

    while (__REG(RTC_BASE_PHYSICAL+RCNR_OFFSET) > old_rcnr);

    /* os timer */
    cli();
    __REG(OST_BASE_PHYSICAL+OSCR0_OFFSET) = 0;
    __REG(OST_BASE_PHYSICAL+OSMR0_OFFSET) = (3250000L)/TIMER_TICK_PER_SEC ; /* Trigger interrupts every 10 ms */
    __REG(OST_BASE_PHYSICAL+OSSR_OFFSET) = 0xFFF;
    __REG(OST_BASE_PHYSICAL+OIER_OFFSET) = OIER_E0;

#if 0 /* Nam9, 2004. 9. 5 */
    /* milli-second timer */
    __REG(OST_BASE_PHYSICAL+OSCR4_OFFSET) = 0;
    /* __REG(OST_BASE_PHYSICAL+OMCR4_OFFSET) = 0xC9; /\* Increase every 1/1000000 sec *\/ */
    __REG(OST_BASE_PHYSICAL+OMCR4_OFFSET) = 0xCC; /* Increase every 1/1000000 sec */
    __REG(OST_BASE_PHYSICAL+OSMR4_OFFSET) = 1000; /* Trigger interrupts every 1 ms */
    __REG(OST_BASE_PHYSICAL+OSSR_OFFSET) = 0xFFF;
    __REG(OST_BASE_PHYSICAL+OIER_OFFSET) = (OIER_E0 | OIER_E4) & 0xFFF;

    /* Interrupt Initailization routine */
    __REG(INTC_BASE_PHYSICAL+ICCR_OFFSET) = 1; /* Only active,unmasked irq. bring processor out of idle mode */
    __REG(INTC_BASE_PHYSICAL+ICLR_OFFSET) = 0;
    __REG(INTC_BASE_PHYSICAL+ICMR_OFFSET) = IRQ_OST0 | IRQ_OST_4_11;
    __REG(INTC_BASE_PHYSICAL+ICMR2_OFFSET) = 0;
#else
    /* Interrupt Initailization routine */
    __REG(INTC_BASE_PHYSICAL+ICCR_OFFSET) = 0;
    __REG(INTC_BASE_PHYSICAL+ICLR_OFFSET) = 0;
    __REG(INTC_BASE_PHYSICAL+ICMR_OFFSET) = IRQ_OST0;
    __REG(INTC_BASE_PHYSICAL+ICMR2_OFFSET) = 0;
#endif
    sti();
}

/* returns the time in seconds */
u32  TimerGetTime(void)
{
    return ( (u32) __REG(RTC_BASE_PHYSICAL+RCNR_OFFSET));
}

/* returns the time in 1/100seconds */
u32  TimerGetCentiTime(void)
{
    return((u32) jiffies/(TIMER_TICK_PER_SEC*100));
}

void ostdelay(int uSec);
void msleep(unsigned int ms)
{
    ostdelay(1000*ms);

// unsigned long init_jiffies;
//
// init_jiffies = jiffies;
//
// while( (init_jiffies + (unsigned long)(ms / 10) ) > jiffies ) {;}
}

void msleep_cli(unsigned int ms)
{
    unsigned long init_jiffies;

    init_jiffies = __REG(OST_BASE_PHYSICAL+OSCR0_OFFSET);

    while ((init_jiffies + (unsigned long)(ms / 10)) > __REG(OST_BASE_PHYSICAL + OSCR0_OFFSET)) {
        ;
    }
}

void ostdelay(int uSec)
{
    unsigned long time = OSCR;
    unsigned long expireTime = time + (uSec * 3);   // approx 3 ticks per uS;

    //
    // Check if we wrapped on the expireTime
    // and delay first part until wrap
    //
    if (expireTime < time) {
        while (time < OSCR) {
        }
    }

    while (OSCR <= expireTime) {
    }

    return ;
}
